classdef ziMFLI < EquipmentControl.ZI.ZurichInstruments
    %ZIMFLI implements MFLI device (5MHz)
    %   example: ziMFLI('dev3546', 'level', 6, 'multiDeviceSync', true)
    %   'level' is the connect level, see zi MFLI manual for detail, default 6
    %   'multiDeviceSync', if true, perform MDS while initialization, default true
    
    properties
        syncDevice % sync devices
    end
    
    methods
        function obj = ziMFLI(dev, varargin)
            %ZIMFLI Construct an instance of ziMFLI
            p=inputParser;
            levelCheck = @(x) isnumeric(x) && ismember(x, 1:6);
            p.addRequired('dev');
            p.addParameter('level', 6, levelCheck);
            p.addParameter('multiDeviceSync', false, @islogical);
            p.parse(dev, varargin{:});
            obj@EquipmentControl.ZI.ZurichInstruments(dev, p.Results.level);

            if p.Results.multiDeviceSync
                obj.multiDeviceSync();
            else
                obj.syncDevice = {dev};
            end
            
        end
        
        function multiDeviceSync(obj)
            % perform MDS
            h = ziDAQ('multiDeviceSyncModule');
            ziDAQ('set', h, 'multiDeviceSyncModule/group', 0);
            ziDAQ('execute', h);
            ziDAQ('set', h, 'multiDeviceSyncModule/start', 1);

            t0 = tic; timeout = 10;
            fprintf('Synchronizing devices ...');

            tmp = ziDAQ('read', h);
            while tmp.status ~= 2
                pause(0.5);
                if toc(t0) > timeout
                    error('Timeout: MultiDevice Synchronizing failed after %f seconds.', timeout)
                end
                tmp = ziDAQ('read', h);
            end

            fprintf('done.\n');
            obj.syncDevice = strsplit( char(cell2mat( tmp.devices )), ',');
        end
        
        %%
        function p = SigInPort(obj)
            p = MeasurementComponent.MachineUnit.IOPort.ZIPort.ziSigInPort(obj);
        end
        function p = CurrInPort(obj)
            p = MeasurementComponent.MachineUnit.IOPort.ZIPort.ziCurrInPort(obj);
        end
        function p = AuxInPort(obj, index)
              p = MeasurementComponent.MachineUnit.IOPort.ZIPort.ziAuxInPort(obj, Miscellaneous.ziIndexStr(index));
        end
        function p = AuxOutPort(obj, index)
            p = MeasurementComponent.MachineUnit.IOPort.ZIPort.ziAuxOutPort(obj, Miscellaneous.ziIndexStr(index));
        end
        function p = SigOutPort(obj)
            p = MeasurementComponent.MachineUnit.IOPort.ZIPort.ziSigOutPort(obj);
        end
        function lia = LockInChannel(obj, index)
            lia = MeasurementComponent.MachineUnit.Analyser.ziLockInChannel(obj, Miscellaneous.ziIndexStr(index));
        end
        %%
        function obj = initializeDemods(obj, ch)
            L = log4m.getLogger;
            if ~isempty(obj.default_settings)
                chStr = Miscellaneous.ziIndexStr(ch);
                dmodsettings = obj.default_settings.demods.(['ch', chStr]);
                obj.setDemodOscSelect(chStr, dmodsettings.oscselect);
                obj.setDemodHarm(chStr, str2double(dmodsettings.harmonic));
                obj.setDemodPhase(chStr, str2double(dmodsettings.phaseshift));
                obj.setInputSignalSelect(chStr, str2double(dmodsettings.adcselect));
                order = str2double(dmodsettings.order); tc = str2double(dmodsettings.timeconstant);
                obj.setDemodFilterOrder(chStr, str2double(dmodsettings.order));
                obj.setDemodFilterBW(chStr, ziTC2BW(tc, order));
                if strcmp(dmodsettings.sinc, '1')
                    obj.enableDemodSinc(chStr);
                else
                    obj.disableDemodSinc(chStr);
                end
                
                if strcmp(dmodsettings.enable, '1')
                    obj.enableDataTransfer(chStr);
                else
                    obj.disableDataTransfer(chStr);
                end
                obj.setDataTransferRate(chStr, str2double(dmodsettings.rate));
                obj.setDataTransferTrigger(chStr, str2double(dmodsettings.trigger));
            else
                L.info('ziMFLI::initializeDemods', 'Default Settings not found. Please load a default setting file first.');
            end
        end
        function obj = initializeOscs(obj, ch)
            L = log4m.getLogger;
            if ~isempty(obj.default_settings)
                chStr = Miscellaneous.ziIndexStr(ch);
                oscsettings = obj.default_settings.oscs.(['ch', chStr]);
                obj.setOscFreq(ch, str2double(oscsettings.freq));
            else
                L.info('ziMFLI::initializeOscs', 'Default Settings not found. Please load a default setting file first.');
            end
        end
        function obj = initializeRefMode(obj, ch)
            L = log4m.getLogger;
            if ~isempty(obj.default_settings)
                chStr = Miscellaneous.ziIndexStr(ch);
                switch chStr
                    case '1'
                        extrefsettings = obj.default_settings.extrefs.ch0;
                        if strcmp(extrefsettings.enable, '1')
                            obj.enableExtRef('0');
                            obj.setExtRefAutoMode('0', str2double(extrefsettings.automode));
                        else
                            obj.disableExtRef('0');
                        end
                    case '3'
                        extrefsettings = obj.default_settings.extrefs.ch1;
                        if strcmp(extrefsettings.enable, '1')
                            obj.enableExtRef('1');
                            obj.setExtRefAutoMode('1', str2double(extrefsettings.automode));
                        else
                            obj.disableExtRef('1');
                        end
                    otherwise
                        % do nothing
                end
            else
                L.info('ziMFLI::initializeRefMode', 'Default Settings not found. Please load a default setting file first.');
            end
        end
        function obj = initializeAmplitude(obj, ch)
            L = log4m.getLogger;
            if ~isempty(obj.default_settings)
                chStr = Miscellaneous.ziIndexStr(ch);
                ampsettings = obj.default_settings.sigouts.ch0.amplitudes; % needs check for UHF, HF2
                enablesettings = obj.default_settings.sigouts.ch0.enables;
                if strcmp(enablesettings.(['ch' chStr]), '1')
                    obj.enableOutAmplitude(chStr);
                else
                    obj.disableOutAmplitude(chStr);
                end
                obj.setSigOutAmplitude(chStr, str2double(ampsettings.(['ch' chStr])));
            else
                L.info('ziMFLI::initializeAmplitude', 'Default Settings not found. Please load a default setting file first.');
            end
        end
        function obj = initializeAuxOut(obj, ch)
            L = log4m.getLogger;
            if ~isempty(obj.default_settings)
                chStr = Miscellaneous.ziIndexStr(ch);
                auxOutsettings = obj.default_settings.auxouts.(['ch' chStr]);
                
                obj.setAuxOutSelect(chStr, str2double(auxOutsettings.outputselect));
                obj.setAuxOutDemodSelect(chStr, str2double(auxOutsettings.demodselect));
                obj.setAuxOutPreOffset(chStr, str2double(auxOutsettings.preoffset));
                obj.setAuxOutScal(chStr, str2double(auxOutsettings.scale));
                obj.setAuxOutOffset(chStr, str2double(auxOutsettings.offset));
                obj.setAuxOutLimitLower(chStr, str2double(auxOutsettings.limitlower));
                obj.setAuxOutLimitUpper(chStr, str2double(auxOutsettings.limitupper));
            else
                L.info('ziMFLI::initializeAuxOut', 'Default Settings not found. Please load a default setting file first.');
            end
        end
        function obj = initializeSigIn(obj)
            L = log4m.getLogger;
            if ~isempty(obj.default_settings)
                siginsettings = obj.default_settings.sigins.ch0;
                if strcmp(siginsettings.ac, '1')
                    obj.enableSigInAC();
                else
                    obj.disableSigInAC();
                end
                if strcmp(siginsettings.diff, '1')
                    obj.enableSigInDiff();
                else
                    obj.disableSigInDiff();
                end
                if strcmp(siginsettings.float, '1')
                    obj.enableSigInFloat();
                else
                    obj.disableSigInFloat();
                end
                if strcmp(siginsettings.imp50, '1')
                    obj.enableSigInImp50();
                else
                    obj.disableSigInImp50();
                end
                
                obj.setSigInRange(str2double(siginsettings.range));
                obj.setSigInScaling(str2double(siginsettings.scaling));
            else
                L.info('ziMFLI::initializeSigIn', 'Default Settings not found. Please load a default setting file first.');
            end
        end
        function obj = initializeSigOut(obj)
            L = log4m.getLogger;
            if ~isempty(obj.default_settings)
                sigoutsettings = obj.default_settings.sigouts.ch0;
                if strcmp(sigoutsettings.on, '1')
                    obj.fireSigOut();
                else
                    obj.silenceSigOut();
                end
                if strcmp(sigoutsettings.imp50, '1')
                    obj.setSigOutImpedance50();
                else
                    obj.setSigOutImpedanceInf();
                end
                pause(0.2);% wait until impedance setting completed.
                obj.setSigOutRange(str2double(sigoutsettings.range));
                
                if strcmp(sigoutsettings.autorange, '1')
                    obj.enableSigOutAutoRange();
                else
                    obj.disableSigOutAutoRange();
                end
                
                obj.setSigOutOffset(str2double(sigoutsettings.offset));
                
                if strcmp(sigoutsettings.add, '1')
                    obj.enableSigOutAdd();
                else
                    obj.disableSigOutAdd();
                end
                
                if strcmp(sigoutsettings.diff, '1')
                    obj.enableSigOutDiff();
                else
                    obj.disableSigOutDiff();
                end
            else
                L.info('ziMFLI::initializeSigOut', 'Default Settings not found. Please load a default setting file first.');
            end
        end
        function obj = initializePID(obj, ch)
            L = log4m.getLogger;
            if ~isempty(obj.default_settings)
                chStr = Miscellaneous.ziIndexStr(ch);
                pidsettings = obj.default_settings.pids.(['ch' chStr]);
                piddemodSettings = pidsettings.demod;
                
                if strcmp(pidsettings.enable, '1')
                    obj.lock(chStr);
                else
                    obj.unLock(chStr);
                end
                obj.setPIDMode(chStr, str2double(pidsettings.mode));
                obj.setPIDAutoMode(chStr, str2double(pidsettings.pll.automode));
                
                obj.setPIDInput(chStr, str2double(pidsettings.input));
                obj.setPIDInputChannel(chStr, pidsettings.inputchannel);
                obj.setPIDSetpoint(chStr, str2double(pidsettings.setpoint));
                if strcmp(pidsettings.phaseunwrap, '1')
                    obj.enablePIDPhaseUnwarp(chStr);
                else
                    obj.disablePIDPhaseUnwarp(chStr);
                end
                order = str2double(piddemodSettings.order); bw = ziTC2BW(str2double(piddemodSettings.timeconstant), order);
                obj.setPIDFilterBW(chStr, bw);
                obj.setPIDFilterOrder(chStr, order);
                obj.setPIDHarmonic(chStr, str2double(piddemodSettings.harmonic));
                
                obj.setPIDOutput(chStr, str2double(pidsettings.output));
                obj.setPIDOutputChannel(chStr, pidsettings.outputchannel);
                obj.setPIDCenter(chStr, str2double(pidsettings.center));
                obj.setPIDLimLower(chStr, str2double(pidsettings.limitlower));
                obj.setPIDLimUpper(chStr, str2double(pidsettings.limitupper));
                
                obj.setPValue(chStr, str2double(pidsettings.p));
                obj.setIValue(chStr, str2double(pidsettings.i));
                obj.setDValue(chStr, str2double(pidsettings.d));
                obj.setDLimValue(chStr, ziTC2BW(str2double(pidsettings.dlimittimeconstant), 1));
                obj.setRateValue(chStr, str2double(pidsettings.rate));
            else
                L.info('ziMFLI::initializePID', 'Default Settings not found. Please load a default setting file first.');
            end
        end
        
        %% Signal Input
        function obj = setRange(obj, val)
            obj.setDblCmd(['/' obj.device '/sigins/0/range'], val);
        end
        function val = getRange(obj)
            val = obj.getDblCmd(['/' obj.device '/sigins/0/range']);
        end
        
        function obj = setSigInRange(obj, val)
            setSigInRange@EquipmentControl.ZI.ZurichInstruments(obj, '0', val);
        end
        function val = getSigInRange(obj)
            val = getSigInRange@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        
        function val = autoRange(obj)
            val = autoRange@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        function obj = setSigInScaling(obj, val)
            setSigInScaling@EquipmentControl.ZI.ZurichInstruments(obj, '0', val);
        end
        function val = getSigInScaling(obj)
            val = getSigInScaling@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        
        function obj = enableSigInAC(obj)
            enableSigInAC@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        function obj = disableSigInAC(obj)
            disableSigInAC@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        function status = getSigInACStatus(obj)
            status = getSigInACStatus@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        
        function obj = enableSigInImp50(obj)
            enableSigInImp50@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        function obj = disableSigInImp50(obj)
            disableSigInImp50@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        function status = getSigInImp50Status(obj)
            status = getSigInImp50Status@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end

        function obj = enableSigInDiff(obj)
            enableSigInDiff@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        function obj = disableSigInDiff(obj)
            disableSigInDiff@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        function status = getSigInDiffStatus(obj)
            status = getSigInDiffStatus@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        
        function obj = enableSigInFloat(obj)
            enableSigInFloat@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        function obj = disableSigInFloat(obj)
            disableSigInFloat@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        function status = getSigInFloatStatus(obj)
            status = getSigInFloatStatus@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        
        function obj = setCurrInRange(obj, val)
            setCurrInRange@EquipmentControl.ZI.ZurichInstruments(obj, '0', val);
        end
        function val = getCurrInRange(obj)
            val = getCurrInRange@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        
        function val = autoRangeCurrIn(obj)
            val = autoRangeCurrIn@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        function obj = setCurrInScaling(obj, val)
            setCurrInScaling@EquipmentControl.ZI.ZurichInstruments(obj, '0', val);
        end
        function val = getCurrInScaling(obj)
            val = getCurrInScaling@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        function obj = enableCurrInFloat(obj)
            enableCurrInFloat@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        function obj = disableCurrInFloat(obj)
            disableCurrInFloat@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        function status = getCurrInFloatStatus(obj)
            status = getCurrInFloatStatus@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        
        %% Signal Output
        function obj = setSigOutOffset(obj, volt)
            setSigOutOffset@EquipmentControl.ZI.ZurichInstruments(obj, '0', volt);
        end
        function  volt = getSigOutOffset(obj)
             volt = getSigOutOffset@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end

        function obj = setSigOutAmplitude(obj, mode, volt) % ZI MFLI has only one Signal Output Channel.
            setSigOutAmplitude@EquipmentControl.ZI.ZurichInstruments(obj, '0', mode, volt);
        end
        function val = getSigOutAmplitude(obj, mode) % ZI MFLI has only one Signal Output Channel.
            val = getSigOutAmplitude@EquipmentControl.ZI.ZurichInstruments(obj, '0', mode);
        end
        
        function obj = disableOutAmplitude(obj, mode)
            if nargin == 1
                mode = '*';
            end
            disableOutAmplitude@EquipmentControl.ZI.ZurichInstruments(obj, '0', mode);
        end
        function obj = enableOutAmplitude(obj, mode)
            if nargin == 1
                mode = '*';
            end
            enableOutAmplitude@EquipmentControl.ZI.ZurichInstruments(obj, '0', mode);
        end
        function status = getOutAmplitudeStatus(obj, mode)
            status = getOutAmplitudeStatus@EquipmentControl.ZI.ZurichInstruments(obj, '0', mode);
        end

        function obj = setSigOutImpedance50(obj)
            % set signal output impedance = 50 Ohm
            obj.setIntCmd(['/' obj.device '/sigouts/0/imp50'], 1);
        end
        function obj = setSigOutImpedanceInf(obj)
            % set signal output impedance = 1M Ohm
            obj.setIntCmd(['/' obj.device '/sigouts/0/imp50'], 0);
        end
        function status = getSigOutImp50Status(obj)
            status = obj.getIntCmd(['/' obj.device '/sigouts/0/imp50']);
        end
        function obj = enableSigOutAutoRange(obj)
            enableSigOutAutoRange@EquipmentControl.ZI.ZurichInstruments(obj,'0');
        end
        function obj = disableSigOutAutoRange(obj)
            disableSigOutAutoRange@EquipmentControl.ZI.ZurichInstruments(obj,'0');
        end
        function status = getSigOutAutoRangeStatus(obj)
            status = getSigOutAutoRangeStatus@EquipmentControl.ZI.ZurichInstruments(obj,'0');
        end
        function obj = setSigOutRange(obj, val)
            setSigOutRange@EquipmentControl.ZI.ZurichInstruments(obj,'0', val);
        end
        function val = getSigOutRange(obj)
            val = getSigOutRange@EquipmentControl.ZI.ZurichInstruments(obj,'0');
        end

        
        function obj = fireSigOut(obj)
            fireSigOut@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        function obj = silenceSigOut(obj)
            silenceSigOut@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        function status = getSigOutStatus(obj)
            status = getSigOutStatus@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        
        function obj = enableSigOutAdd(obj)
            enableSigOutAdd@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        function obj = disableSigOutAdd(obj)
            disableSigOutAdd@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        function status = getSigOutAddStatus(obj)
            status = getSigOutAddStatus@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        
        function obj = enableSigOutDiff(obj)
            enableSigOutDiff@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        function obj = disableSigOutDiff(obj)
            disableSigOutDiff@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        function status = getSigOutDiffStatus(obj)
            status = getSigOutDiffStatus@EquipmentControl.ZI.ZurichInstruments(obj, '0');
        end
        
        %% PID
        function obj = lock(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            obj.setIntCmd(['/' obj.device '/pids/' ch '/enable'], 1);
        end
        function obj = unLock(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            obj.setIntCmd(['/' obj.device '/pids/' ch '/enable'], 0);
        end
        function val = getLockStatus(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            val = obj.getIntCmd(['/' obj.device '/pids/' ch '/enable']);
        end
        
        function obj = setPValue(obj, ch, val)
            ch = Miscellaneous.ziIndexStr(ch);
            obj.setDblCmd(['/' obj.device '/pids/' ch '/p'], val);
        end
        function val = getPValue(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            val = obj.getDblCmd(['/' obj.device '/pids/' ch '/p']);
        end

        function obj = setIValue(obj, ch, val)
            ch = Miscellaneous.ziIndexStr(ch);
            obj.setDblCmd(['/' obj.device '/pids/' ch '/i'], val);
        end
        function val = getIValue(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            val = obj.getDblCmd(['/' obj.device '/pids/' ch '/i']);
        end
        
        function obj = setDValue(obj, ch, val)
            ch = Miscellaneous.ziIndexStr(ch);
            obj.setDblCmd(['/' obj.device '/pids/' ch '/d'], val);
        end
        function val = getDValue(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            val = obj.getDblCmd(['/' obj.device '/pids/' ch '/d']);
        end
        
        function obj = setDLimValue(obj, ch, val)
            ch = Miscellaneous.ziIndexStr(ch);
            obj.setDblCmd(['/' obj.device '/pids/' ch '/dlimittimeconstant'], ziBW2TC(val, 1));
        end
        function val = getDLimValue(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            val = obj.getDblCmd(['/' obj.device '/pids/' ch '/dlimittimeconstant']);
        end
        
        function obj = setRateValue(obj, ch, val)
            ch = Miscellaneous.ziIndexStr(ch);
            obj.setDblCmd(['/' obj.device '/pids/' ch '/rate'], val);
        end
        function val = getRateValue(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            val = obj.getDblCmd(['/' obj.device '/pids/' ch '/rate']);
        end
        
        function obj = setPIDCenter(obj, ch, val)
            ch = Miscellaneous.ziIndexStr(ch);
            obj.setDblCmd(['/' obj.device '/pids/' ch '/center'], val);
        end
        function val = getPIDCenter(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            val = obj.getDblCmd(['/' obj.device '/pids/' ch '/center']);
        end
        
        function obj = setPIDLimLower(obj, ch, val)
            ch = Miscellaneous.ziIndexStr(ch);
            obj.setDblCmd(['/' obj.device '/pids/' ch '/limitlower'], val);
        end
        function val = getPIDLimLower(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            val = obj.getDblCmd(['/' obj.device '/pids/' ch '/limitlower']);
        end
        
        function obj = setPIDLimUpper(obj, ch, val)
            ch = Miscellaneous.ziIndexStr(ch);
            obj.setDblCmd(['/' obj.device '/pids/' ch '/limitupper'], val);
        end
        function val = getPIDLimUpper(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            val = obj.getDblCmd(['/' obj.device '/pids/' ch '/limitupper']);
        end
        
        function obj = setPIDMode(obj, ch, val)
            ch = Miscellaneous.ziIndexStr(ch);
            obj.setIntCmd(['/' obj.device '/pids/' ch '/mode'], val);
        end
        function val = getPIDMode(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            val = obj.getIntCmd(['/' obj.device '/pids/' ch '/mode']);
        end
        function obj = setPIDAutoMode(obj, ch, val)
            ch = Miscellaneous.ziIndexStr(ch);
            obj.setIntCmd(['/' obj.device '/pids/' ch '/pll/automode'], val);
        end
        function val = getPIDAutoMode(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            val = obj.getIntCmd(['/' obj.device '/pids/' ch '/pll/automode']);
        end
        
        function obj = setPIDInput(obj, ch, val)
            ch = Miscellaneous.ziIndexStr(ch);
            obj.setIntCmd(['/' obj.device '/pids/' ch '/input'], val);
        end
        function val = getPIDInput(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            val = obj.getIntCmd(['/' obj.device '/pids/' ch '/input']);
        end
        
        function obj = setPIDOutput(obj, ch, val)
            ch = Miscellaneous.ziIndexStr(ch);
            obj.setIntCmd(['/' obj.device '/pids/' ch '/output'], val);
        end
        function val = getPIDOutput(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            val = obj.getIntCmd(['/' obj.device '/pids/' ch '/output']);
        end
        
        function obj = setPIDInputChannel(obj, ch, val)
            ch = Miscellaneous.ziIndexStr(ch);
            obj.setIntCmd(['/' obj.device '/pids/' ch '/inputchannel'], val);
        end
        function val = getPIDInputChannel(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            val = obj.getIntCmd(['/' obj.device '/pids/' ch '/inputchannel']);
        end
        
        function obj = setPIDOutputChannel(obj, ch, val)
            ch = Miscellaneous.ziIndexStr(ch);
            obj.setIntCmd(['/' obj.device '/pids/' ch '/outputchannel'], val);
        end
        function val = getPIDOutputChannel(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            val = obj.getIntCmd(['/' obj.device '/pids/' ch '/outputchannel']);
        end
        
        function obj = setPIDSetpoint(obj, ch, val)
            ch = Miscellaneous.ziIndexStr(ch);
            obj.setDblCmd(['/' obj.device '/pids/' ch '/setpoint'], val);
        end        
        function val = getPIDSetpoint(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            val = obj.getDblCmd(['/' obj.device '/pids/' ch '/setpoint']);
        end
        
        function obj = setPIDFilterBW(obj, ch, val)
            ch = Miscellaneous.ziIndexStr(ch);
            order = obj.getPIDFilterOrder(ch);
            obj.setDblCmd(['/' obj.device '/pids/' ch '/demod/timeconstant'], ziBW2TC(val, order) );
        end        
        function val = getPIDFilterBW(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            order = obj.getPIDFilterOrder(ch);
            val = ziTC2BW(obj.getDblCmd(['/' obj.device '/pids/' ch '/demod/timeconstant']), order);
        end
        
        function obj = setPIDFilterOrder(obj, ch, val)
            ch = Miscellaneous.ziIndexStr(ch);
            obj.setIntCmd(['/' obj.device '/pids/' ch '/demod/order'], val);
        end
        function val = getPIDFilterOrder(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            val = obj.getIntCmd(['/' obj.device '/pids/' ch '/demod/order']);
        end
        
        function obj = setPIDHarmonic(obj, ch, val)
            ch = Miscellaneous.ziIndexStr(ch);
            obj.setDblCmd(['/' obj.device '/pids/' ch '/demod/harmonic'], val);
        end
        function val = getPIDHarmonic(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            val = obj.getDblCmd(['/' obj.device '/pids/' ch '/demod/harmonic']);
        end
        
        function obj = enablePIDPhaseUnwarp(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            obj.setIntCmd(['/' obj.device '/pids/' ch '/phaseunwrap'], 1);
        end 
        function obj = disablePIDPhaseUnwarp(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            obj.setIntCmd(['/' obj.device '/pids/' ch '/phaseunwrap'], 0);
        end 
        function val = getPIDPhaseUnwarpStatus(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            val = obj.getIntCmd(['/' obj.device '/pids/' ch '/phaseunwrap']);
        end 
        
        function obj = setPIDStreamValue(obj, ch, val)
            ch = Miscellaneous.ziIndexStr(ch);
            obj.setDblCmd(['/' obj.device '/pids/' ch '/stream/rate'], val);
        end
        function val = getPIDStreamValue(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            val = obj.getDblCmd(['/' obj.device '/pids/' ch '/stream/effectiverate']);
        end
        
        function val = getPIDError(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            val = obj.getDblCmd(['/' obj.device '/pids/' ch '/error']);
        end
        
        function [value, time] = pollPIDError(obj, ch, duration)
            ch = Miscellaneous.ziIndexStr(ch);
            path = ['/' obj.device '/pids/' ch '/error'];
            ziDAQ('unsubscribe', '*');
            ziDAQ('subscribe', path);
            data = ziDAQ('poll', duration, 10e-3);
            ziDAQ('unsubscribe', path);
            data = data.(obj.device).pids(str2double(ch)+1).error;
            timebase = obj.getDblCmd(['/' obj.device '/system/properties/timebase']);
            value = data.value;
            time = double(data.timestamp - data.timestamp(1))*timebase;
        end
        
        function val = getPIDShift(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            val = obj.getDblCmd(['/' obj.device '/pids/' ch '/shift']);
        end
        
        function val = getPIDValue(obj, ch)
            ch = Miscellaneous.ziIndexStr(ch);
            val = obj.getDblCmd(['/' obj.device '/pids/' ch '/value']);
        end

        %% display settings
        function settings = showInputSettings(obj)
            settings.scaling = obj.getSigInScaling();
            settings.coupling = obj.getSigInACStatus();
            settings.impedance = obj.getSigInImp50Status();
            settings.diff = obj.getSigInDiffStatus();
            settings.float = obj.getSigInFloatStatus();
            disp(settings);
        end
        
        function settings = showOutputSettings(obj)
            settings.offset = obj.getSigOutOffset();
            settings.amplitude = obj.getSigOutAmplitude();
            settings.amplitudeStauts = obj.getOutAmplitudeStatus();
            settings.impedance = obj.getSigOutImp50Status();
            settings.outputStatus = obj.getSigOutStatus();
            settings.addStatus = obj.getSigOutAddStatus();
            settings.diffStatus = obj.getSigOutDiffStatus();
            disp(settings);
        end
        
        function settings = showDemodSettings(obj, ch)
            settings.osc = obj.getDemodOscSelect(ch);
            settings.phase = obj.getDemodPhase(ch);
            settings.harm = obj.getDemodHarm(ch);
            settings.input = obj.getInputSignalSelect(ch);
            settings.order = obj.getDemodFilterOrder(ch);
            settings.bw3db = obj.getDemodFilterBW(ch);
            settings.transStatus = obj.getDataTransferStatus(ch);
            settings.transRate = obj.setDataTranferRate(ch);
            disp(settings);
        end
        
        function settings = showAuxSettings(obj, ch)
            settings.modeSel = obj.getAuxOutSelect(ch);
            settings.scale = obj.getAuxOutScal(ch);
            settings.lower = obj.getAuxOutLimitLower(ch);
            settings.upper = obj.getAuxOutLimitUpper(ch);
            settings.offset = obj.getAuxOutOffset(ch);
        end

    end
end

